// 引入登录/退出/获取用户的api接口函数
import { login, logout, getInfo } from '@/api/acl/user'
// 引入获取token/保存token/移除token的函数
import { getToken, setToken, removeToken } from '@/utils/auth'
// 引入重置路由的函数
import { resetRouter } from '@/router'

// 引入路由器对象
import router from '@/router'
// 引入常量路由 异步路由 任意路由
import {constantRoutes,asyncRoutes,anyRoutes} from '@/router/routes'
// 引入深拷贝
import cloneDeep from 'lodash/cloneDeep'

// 初始化state对象的回调函数
const getDefaultState = () => {
  return {
    token: getToken(), // token
    name: '', // 用户名字
    avatar: '', // 头像
    buttons:[], //按钮权限相关的数组
    roles:[],   // 角色权限相关的数组
    asyncRoutes:[],  //路由权限相关的数组
    routes: []       //所有路由相关的数组
  }
}
// 创建一个state对象
const state = getDefaultState()

// mutations对象
const mutations = {
  // 重置state对象
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  // 保存token
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  // 保存用户名字
  SET_NAME: (state, name) => {
    state.name = name
  },
  // 保存头像信息
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  },
  // 保存用户信息
  SET_USER:(state,{avatar,buttons,roles,name}) => {
    state.avatar = avatar
    state.buttons = buttons
    state.roles = roles
    state.name = name
  },
  // 
  SET_ROUTES(state,asyncRoutes){
    // 一定是合并后的 已经过滤后的动态路由的数组
    state.asyncRoutes = asyncRoutes
    // 合并路由数组
    state.routes = constantRoutes.concat(asyncRoutes,anyRoutes)
    // 再把异步路由和任意录音重新加入到常量路由中 从而真正的在路由器中合并路由数据
    router.addRoutes([...asyncRoutes,anyRoutes])
  }
}
// actions对象
const actions = {
  // 登录的action
  login ({ commit }, userInfo) {
    // 解构出帐号和密码
    const { username, password } = userInfo
    return new Promise((resolve, reject) => {
      // 调用login的api接口函数,并传入帐号和密码
      login({ username: username.trim(), password: password }).then(response => {
        // 登录成功后解构出所需要的data数据
        const { data } = response
        // 提交保存token的mutation
        commit('SET_TOKEN', data.token)
        // 使用cookies的方式存储token
        setToken(data.token)
        resolve()
      }).catch(error => {
        // 登录失败了
        reject(error)
      })
    })
  },

  // 获取用户信息的action
  getInfo({ commit, state }) {
    return new Promise((resolve, reject) => {
      // 获取用户信息,不需要传入token
      getInfo().then(response => {
        // 解构出所需的data数据
        const { data } = response
        if (!data) {
          // 如果没有用户信息,则提示,重新的进行登录
          // 程序员开发的项目一定要懂得尊重用户
          return reject('请您重新登录')
        }
        // 保存用户信息到Vuex中
        commit('SET_USER',data)
        console.log(data)
        // 过滤路由对象信息数据 并保存到Vuex中
        const resultRoutes = filterAsyncRoutes(cloneDeep(asyncRoutes),data.routes)
        commit('SET_ROUTES',resultRoutes)
        // // 解构出用户的名字和头像
        // const { name, avatar } = data
        // // 保存用户名
        // commit('SET_NAME', name)
        // // 保存头像
        // commit('SET_AVATAR', avatar)
        resolve(data)
      }).catch(error => {
        reject(error)
      })
    })
  },

  // 退出的action
  logout({ commit, state }) {
    return new Promise((resolve, reject) => {
      logout(state.token).then(() => {
        removeToken() // 移除token
        resetRouter() // 重置路由
        commit('RESET_STATE') // 重置state
        resolve()
      }).catch(error => {
        reject(error)
      })
    })
  },

  // 移除token的action
  resetToken({ commit }) {
    return new Promise(resolve => {
      removeToken() // 移除token
      commit('RESET_STATE') // 重置state
      resolve()
    })
  }
}
// ***递归过滤异步路由表，返回符合用户菜单权限的路由表
// 封装过滤路由对象信息数据的函数
function filterAsyncRoutes(routes,routeNames){
  return routes.filter(route => {
    // 判断当前的路由对象的名字中是否存在路由名字数组中
    if(routeNames.includes(route.name)){
      // 当前的路由对象中有没有子路由
      if(route.children && route.children.length > 0){
        // 判断 子路由中是否还有子路由对象 如果有的话就递归调用
        const cRoute = filterAsyncRoutes(route.children,routeNames)
        // 判断子路由是否存在 如果过滤一圈没有子元素了 那么父级菜单也就不显示了
        if(cRoute && cRoute.length > 0){
          route.children = cRoute
          return true
        }
        return false
      }
      return true
    }
    return false
  })
}


// 暴露出去user对象
export default {
  namespaced: true, // 开启命名空间
  state,
  mutations,
  actions
}

